﻿using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Collections.Generic;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using WxLib.Common;
using WxLib.Core.Util;
using WxLib.Core.RequestHandlers;
using WxLib.Core.Serializers;
namespace WxLib.TemplateMessage
{
    /*下发条件说明
支付

当用户在小程序内完成过支付行为，可允许开发者向用户在7天内推送有限条数的模板消息（1次支付可下发3条，多次支付下发条数独立，互相不影响）

提交表单

当用户在小程序内发生过提交表单行为且该表单声明为要发模板消息的，开发者需要向用户提供服务时，可允许开发者向用户在7天内推送有限条数的模板消息（1次提交表单可下发1条，多次提交下发条数独立，相互不影响）
    */
    /// <summary>
    /// 微信模板消息
    /// </summary>
    public class WxTemplateMessageApi
    {
        private string defaultUri = "https://api.weixin.qq.com";
        private readonly WxApiOptions options;

        public WxTemplateMessageApi(IOptions<WxApiOptions> optionsAccessor)
        {
            BaseUri = new Uri(defaultUri);
            RequestHandler = new RequestHandler(new JsonSerializer());
            options = optionsAccessor.Value;
        }


        /// <summary>
        /// 获取或设置用于执行请求的RequestHandler
        /// </summary>
        public IPostRequestHandler RequestHandler;

        /// <summary>
        /// 获取或设置请求的基本URI。
        /// </summary>
        public Uri BaseUri { get; set; }

        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <param name="to_openid"></param>
        /// <param name="page"></param>
        /// <param name="form_id"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task<SendMsgResult> SendAsync(string to_openid, string page, string form_id, WxTemplateMessage message)
        {
            Contract.Requires(message != null, "message cannot be null.");
            return await SendAsync(to_openid, message.templateId, page, form_id, message.emphasisKeyword, message.messageData);
        }

        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <param name="to_openid"></param>
        /// <param name="page"></param>
        /// <param name="form_id"></param>
        /// <param name="emphasisKeyword">模板需要放大的关键词，不填则默认无放大</param>
        /// <param name="message"></param>
        /// <returns></returns>
        public SendMsgResult Send(string to_openid, string page, string form_id, WxTemplateMessage message)
        {
            return SendAsync(to_openid, page, form_id, message).Result;
        }
        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <param name="to_openid">接收者（用户）的 openid</param>
        /// <param name="template_id">所需下发的模板消息的id</param>
        /// <param name="page">点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转。</param>
        /// <param name="form_id">表单提交场景下，为 submit 事件带上的 formId；支付场景下，为本次支付的 prepay_id</param>
        /// <param name="emphasisKeyword">模板需要放大的关键词，不填则默认无放大</param>
        /// <param name="data">模板内容，不填则下发空模板</param>
        /// <returns></returns>
        public async Task<SendMsgResult> SendAsync(string to_openid, string template_id, string page, string form_id, string emphasisKeyword, Dictionary<string, MessageKeyword> data)
        {
            Contract.Requires(to_openid != null, "to_openid cannot be null.");
            Contract.Requires(template_id != null, "template_id cannot be null.");
            Contract.Requires(form_id != null, "form_id cannot be null.");
            WxAccessTokenResponse response = await WxCommonApi.Instance().GetAccessTokenAsync(options.AppId, options.AppSecret);
            Contract.Requires(response != null, "access_token be null.");
            var relUri = "/cgi-bin/message/wxopen/template/send?access_token=" + response.access_token;
            SendMsgOptions sendMsgOptions = new SendMsgOptions();
            sendMsgOptions.touser = to_openid;
            sendMsgOptions.template_id = template_id;
            sendMsgOptions.page = page;
            sendMsgOptions.form_id = form_id;
            sendMsgOptions.data = data;
            if (!string.IsNullOrEmpty(emphasisKeyword))
            {
                sendMsgOptions.emphasis_keyword = (emphasisKeyword.EndsWith(".DATA") ? emphasisKeyword : emphasisKeyword + ".DATA");
            }
            var queryString = RequestHandler.Serializer.Serialize(sendMsgOptions);
            var result = await requestAsync<SendMsgResult>(relUri, queryString);
            if (result.errcode == 42001 || result.errcode == 40001)
            {
                WxCommonApi.Instance().Reload = true;
            }
            return result;
        }

        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <param name="to_openid">接收者（用户）的 openid</param>
        /// <param name="template_id">所需下发的模板消息的id</param>
        /// <param name="page">点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转。</param>
        /// <param name="form_id">表单提交场景下，为 submit 事件带上的 formId；支付场景下，为本次支付的 prepay_id</param>
        /// <param name="emphasisKeyword">模板需要放大的关键词，不填则默认无放大</param>
        /// <param name="data">模板内容，不填则下发空模板</param>
        /// <returns></returns>
        public SendMsgResult Send(string to_openid, string template_id, string page, string form_id, string emphasisKeyword, Dictionary<string, MessageKeyword> data)
        {
            return SendAsync(to_openid, template_id, page, form_id, emphasisKeyword, data).Result;
        }


        /// <summary>
        /// 异步请求 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="relUri"></param>
        /// <param name="queryString"></param>
        /// <returns></returns>
        private async Task<T> requestAsync<T>(string relUri, string queryString)
        {
            return await RequestHandler.PostRequestAsync<T>(new Uri(BaseUri, relUri), queryString).ConfigureAwait(false);
        }
    }
}
